<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weston Calibration Protocol Tool</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.2);
            overflow: hidden;
        }

        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            text-align: center;
        }

        .header h1 {
            font-size: 28px;
            margin-bottom: 5px;
        }

        .header p {
            font-size: 14px;
            opacity: 0.9;
        }

        .tabs {
            display: flex;
            background: #f5f5f5;
            border-bottom: 2px solid #667eea;
        }

        .tab-button {
            flex: 1;
            padding: 15px;
            background: transparent;
            border: none;
            cursor: pointer;
            font-size: 16px;
            font-weight: bold;
            color: #666;
            transition: all 0.3s;
        }

        .tab-button.active {
            background: white;
            color: #667eea;
            border-bottom: 3px solid #667eea;
        }

        .tab-content {
            display: none;
            padding: 30px;
        }

        .tab-content.active {
            display: block;
        }

        .form-group {
            margin-bottom: 20px;
        }

        .form-group label {
            display: block;
            margin-bottom: 8px;
            color: #333;
            font-weight: bold;
            font-size: 14px;
        }

        .form-group input,
        .form-group select,
        .form-group textarea {
            width: 100%;
            padding: 10px;
            border: 2px solid #e0e0e0;
            border-radius: 8px;
            font-size: 14px;
            transition: border-color 0.3s;
            font-family: 'Courier New', monospace;
        }

        .form-group input:focus,
        .form-group select:focus,
        .form-group textarea:focus {
            outline: none;
            border-color: #667eea;
        }

        .form-row {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
        }

        .phase-section {
            background: #f9f9f9;
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 15px;
            border-left: 4px solid #667eea;
        }

        .phase-title {
            font-weight: bold;
            color: #667eea;
            margin-bottom: 10px;
            font-size: 16px;
        }

        .button-group {
            display: flex;
            gap: 10px;
            margin-top: 20px;
        }

        .btn {
            padding: 12px 30px;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
        }

        .btn-primary {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }

        .btn-primary:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        .btn-secondary {
            background: #f5f5f5;
            color: #666;
        }

        .btn-secondary:hover {
            background: #e0e0e0;
        }

        .result-box {
            margin-top: 20px;
            padding: 20px;
            background: #f9f9f9;
            border-radius: 8px;
            border: 2px solid #e0e0e0;
        }

        .result-title {
            font-weight: bold;
            color: #667eea;
            margin-bottom: 10px;
            font-size: 18px;
        }

        .result-content {
            background: white;
            padding: 15px;
            border-radius: 5px;
            font-family: 'Courier New', monospace;
            font-size: 13px;
            word-break: break-all;
            max-height: 300px;
            overflow-y: auto;
        }

        .parsed-data {
            margin-top: 15px;
        }

        .parsed-item {
            background: white;
            padding: 8px;
            margin-bottom: 5px;
            border-radius: 5px;
            border-left: 3px solid #667eea;
        }

        .parsed-label {
            font-weight: bold;
            color: #667eea;
            display: inline-block;
            min-width: 150px;
        }

        .checkbox-group {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .checkbox-group input[type="checkbox"] {
            width: auto;
            cursor: pointer;
        }

        .info-box {
            background: #e3f2fd;
            border-left: 4px solid #2196f3;
            padding: 12px;
            margin-bottom: 20px;
            border-radius: 5px;
            font-size: 13px;
            color: #1565c0;
        }

        /* Read-only form styles */
        .readonly-notice {
            background: #f5f5f5;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 15px;
            margin-bottom: 20px;
            display: flex;
            align-items: center;
            gap: 12px;
        }

        .notice-icon {
            font-size: 24px;
            opacity: 0.7;
        }

        .notice-text {
            color: #666;
            line-height: 1.4;
        }

        .notice-text strong {
            color: #333;
            font-weight: 600;
        }

        .readonly-group {
            opacity: 0.7;
            background: #fafafa;
            border: 1px solid #e0e0e0;
            border-radius: 6px;
            padding: 15px;
            margin-bottom: 15px;
        }

        .readonly-group label {
            color: #666;
            font-weight: 600;
            margin-bottom: 10px;
            display: block;
        }

        .readonly-info {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .info-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 6px 0;
            border-bottom: 1px solid #eee;
        }

        .info-item:last-child {
            border-bottom: none;
        }

        .info-label {
            font-weight: 500;
            color: #666;
            min-width: 120px;
        }

        .info-value {
            color: #333;
            font-family: 'Courier New', monospace;
            font-size: 13px;
            background: #f0f0f0;
            padding: 2px 6px;
            border-radius: 3px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>Weston Calibration Protocol Tool</h1>
            <p>Protocol Composition & Parsing</p>
        </div>

        <div class="tabs">
            <button class="tab-button active" onclick="switchTab('compose')">Compose Frame</button>
            <button class="tab-button" onclick="switchTab('parse')">Parse Frame</button>
            <button class="tab-button" onclick="switchTab('serial')">Serial Test</button>
        </div>

        <!-- Protocol Composition -->
        <div id="compose" class="tab-content active">
            <div class="info-box">
                <strong>Note:</strong> Select calibration type, fill in parameters, then click "Compose" to generate protocol frame.
            </div>

            <div class="form-group">
                <label>Select Calibration Type:</label>
                <select id="calibrationType" onchange="showCalibrationForm()">
                    <option value="preparation">Calibration Preparation</option>
                    <option value="init">Calibration Parameter Initialization</option>
                    <option value="fundamental">Fundamental Calibration</option>
                    <option value="harmonic">Harmonic Calibration</option>
                    <option value="pulse">Set Pulse Constant</option>
                    <option value="harmonicCount">Set Harmonic Order</option>
                </select>
            </div>

            <!-- Calibration Preparation Form -->
            <div id="preparationForm" class="calibration-form" style="display: none;">
                <div class="info-box">
                    <strong>Note:</strong> This command prepares the meter for calibration. No parameters required.
                </div>
            </div>

            <!-- Calibration Parameter Initialization Form -->
            <div id="initForm" class="calibration-form" style="display: none;">
                <div class="info-box">
                    <strong>Note:</strong> This command initializes calibration parameters. No parameters required.
                </div>
            </div>

            <!-- Fundamental Calibration Form -->
            <div id="fundamentalForm" class="calibration-form">
                <div class="form-group">
                    <label>Calibration Point Index (0~4):</label>
                    <input type="number" id="fundamentalPointIndex" min="0" max="4" value="0">
                </div>

                <div class="form-group">
                    <label class="checkbox-group">
                        <input type="checkbox" id="fundamentalIsLast"> Is Last Calibration Point
                    </label>
                </div>

                <div class="phase-section">
                    <div class="phase-title">Phase A Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase A Voltage (V):</label>
                            <input type="number" id="fundamentalAVoltage" step="0.0001" value="57.7">
                        </div>
                        <div class="form-group">
                            <label>Phase A Current (A):</label>
                            <input type="number" id="fundamentalACurrent" step="0.00001" value="1.5">
                        </div>
                        <div class="form-group">
                            <label>Phase A Phase (deg):</label>
                            <input type="number" id="fundamentalAPhase" step="0.0001" value="59.9992">
                        </div>
                    </div>
                </div>

                <div class="phase-section">
                    <div class="phase-title">Phase B Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase B Voltage (V):</label>
                            <input type="number" id="fundamentalBVoltage" step="0.0001" value="57.7">
                        </div>
                        <div class="form-group">
                            <label>Phase B Current (A):</label>
                            <input type="number" id="fundamentalBCurrent" step="0.00001" value="1.5">
                        </div>
                        <div class="form-group">
                            <label>Phase B Phase (deg):</label>
                            <input type="number" id="fundamentalBPhase" step="0.0001" value="59.9992">
                        </div>
                    </div>
                </div>

                <div class="phase-section">
                    <div class="phase-title">Phase C Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase C Voltage (V):</label>
                            <input type="number" id="fundamentalCVoltage" step="0.0001" value="57.7">
                        </div>
                        <div class="form-group">
                            <label>Phase C Current (A):</label>
                            <input type="number" id="fundamentalCCurrent" step="0.00001" value="1.5">
                        </div>
                        <div class="form-group">
                            <label>Phase C Phase (deg):</label>
                            <input type="number" id="fundamentalCPhase" step="0.0001" value="59.9992">
                        </div>
                    </div>
                </div>
            </div>

            <!-- Harmonic Calibration Form -->
            <div id="harmonicForm" class="calibration-form" style="display: none;">
                <div class="form-group">
                    <label>Harmonic Order:</label>
                    <select id="harmonicOrder">
                        <option value="2">2nd Harmonic</option>
                        <option value="3">3rd Harmonic</option>
                        <option value="5">5th Harmonic</option>
                        <option value="11">11th Harmonic</option>
                        <option value="21">21st Harmonic</option>
                        <option value="31">31st Harmonic</option>
                        <option value="41">41st Harmonic</option>
                    </select>
                </div>

                <div class="form-group">
                    <label>Calibration Point Index (0~2):</label>
                    <input type="number" id="harmonicPointIndex" min="0" max="2" value="0">
                    <small style="color: #666; font-size: 12px;">0=40%, 1=5%, 2=1% (harmonic current content from high to low)</small>
                </div>

                <div class="form-group">
                    <label>Harmonic Order Index (0~6):</label>
                    <input type="number" id="harmonicOrderIndex" min="0" max="6" value="0">
                    <small style="color: #666; font-size: 12px;">0=2nd, 1=3rd, 2=5th, 3=11th, 4=21st, 5=31st, 6=41st</small>
                </div>

                <div class="form-group">
                    <label>
                        <input type="checkbox" id="harmonicLastPoint" style="width: auto; margin-right: 8px;">
                        Last Calibration Point (Entire Process)
                    </label>
                    <small style="color: #666; font-size: 12px; display: block; margin-top: 5px;">
                        Check this ONLY if this is the very last calibration point of the entire harmonic calibration process (Frame 21)
                    </small>
                </div>

                <div class="phase-section">
                    <div class="phase-title">Phase A Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase A Harmonic Voltage (%)</label>
                            <input type="number" id="harmonicAVoltage" step="0.0001" value="5.0">
                        </div>
                        <div class="form-group">
                            <label>Phase A Harmonic Current (%)</label>
                            <input type="number" id="harmonicACurrent" step="0.0001" value="40.0">
                        </div>
                        <div class="form-group">
                            <label>Phase A Phase (deg):</label>
                            <input type="number" id="harmonicAPhase" step="0.0001" value="59.9992">
                        </div>
                    </div>
                </div>

                <div class="phase-section">
                    <div class="phase-title">Phase B Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase B Harmonic Voltage (%)</label>
                            <input type="number" id="harmonicBVoltage" step="0.0001" value="5.0">
                        </div>
                        <div class="form-group">
                            <label>Phase B Harmonic Current (%)</label>
                            <input type="number" id="harmonicBCurrent" step="0.0001" value="40.0">
                        </div>
                        <div class="form-group">
                            <label>Phase B Phase (deg):</label>
                            <input type="number" id="harmonicBPhase" step="0.0001" value="59.9992">
                        </div>
                    </div>
                </div>

                <div class="phase-section">
                    <div class="phase-title">Phase C Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase C Harmonic Voltage (%)</label>
                            <input type="number" id="harmonicCVoltage" step="0.0001" value="5.0">
                        </div>
                        <div class="form-group">
                            <label>Phase C Harmonic Current (%)</label>
                            <input type="number" id="harmonicCCurrent" step="0.0001" value="40.0">
                        </div>
                        <div class="form-group">
                            <label>Phase C Phase (deg):</label>
                            <input type="number" id="harmonicCPhase" step="0.0001" value="59.9992">
                        </div>
                    </div>
                </div>
            </div>

            <!-- Pulse Constant Form -->
            <div id="pulseForm" class="calibration-form" style="display: none;">
                <div class="form-group">
                    <label>Wiring Mode:</label>
                    <select id="wireMode">
                        <option value="3">3-Phase 3-Wire</option>
                        <option value="4">3-Phase 4-Wire</option>
                    </select>
                </div>

                <div class="form-group">
                    <label>Fundamental Pulse Constant:</label>
                    <input type="number" id="fundamentalPulseConstant" value="20000">
                </div>

                <div class="form-group">
                    <label>Harmonic Pulse Constant:</label>
                    <input type="number" id="harmonicPulseConstant" value="200000">
                </div>
            </div>

            <!-- Harmonic Count Form -->
            <div id="harmonicCountForm" class="calibration-form" style="display: none;">
                <div class="form-group">
                    <label>Current Harmonic Order:</label>
                    <select id="currentHarmonicOrder">
                        <option value="2">2nd Harmonic</option>
                        <option value="3">3rd Harmonic</option>
                        <option value="5">5th Harmonic</option>
                        <option value="11">11th Harmonic</option>
                        <option value="21">21st Harmonic</option>
                        <option value="31">31st Harmonic</option>
                        <option value="41">41st Harmonic</option>
                    </select>
                </div>

                <div class="form-group">
                    <label>Harmonic Order Index (0~6):</label>
                    <input type="number" id="currentHarmonicOrderIndex" min="0" max="6" value="0">
                    <small style="color: #666; font-size: 12px;">0=2nd, 1=3rd, 2=5th, 3=11th, 4=21st, 5=31st, 6=41st</small>
                </div>
            </div>

            <div class="button-group">
                <button class="btn btn-primary" onclick="composeFrame()">Compose</button>
                <button class="btn btn-secondary" onclick="clearComposeForm()">Clear</button>
            </div>

            <div id="composeResult" class="result-box" style="display: none;">
                <div class="result-title">Generated Protocol Frame:</div>
                <div class="result-content" id="composeResultContent"></div>
            </div>
        </div>

        <!-- Protocol Parsing -->
        <div id="parse" class="tab-content">
            <div class="info-box">
                <strong>Note:</strong> Enter protocol frame (space separated), then click "Parse" to view results.
            </div>

            <div class="form-group">
                <label>Protocol Frame:</label>
                <textarea id="parseInput" rows="5" placeholder="FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E..."></textarea>
            </div>

            <div class="button-group">
                <button class="btn btn-primary" onclick="parseFrame()">Parse</button>
                <button class="btn btn-secondary" onclick="clearParseForm()">Clear</button>
            </div>

            <div id="parseResult" class="result-box" style="display: none;">
                <div class="result-title">Parse Results:</div>
                <div class="parsed-data" id="parseResultContent"></div>
            </div>

            <!-- Editable Form for Parsed Data -->
            <div id="editableForm" class="result-box" style="display: none;">
                <div class="result-title">Edit Parameters & Compose:</div>
                <div id="editableFormContent"></div>
                <div class="button-group">
                    <button class="btn btn-primary" onclick="composeFromParsed()">Compose New Frame</button>
                    <button class="btn btn-secondary" onclick="hideEditableForm()">Cancel</button>
                </div>
            </div>

            <!-- Compose Result from Parsed Data -->
            <div id="composeFromParseResult" class="result-box" style="display: none;">
                <div class="result-title">Generated Frame from Parsed Data:</div>
                <div class="result-content" id="composeFromParseResultContent"></div>
            </div>
        </div>

        <!-- Serial Communication Test -->
        <div id="serial" class="tab-content">
            <div class="info-box">
                <strong>How to Connect:</strong><br>
                1. Click "Connect" button to select your serial port<br>
                2. Configure baud rate and other settings<br>
                3. Select a test frame and click "Send Frame" to test<br>
                4. Or click "Send All Frames" to send all 21 calibration frames<br>
                <br>
                <strong>Note:</strong> "No ports available" is normal for first-time use. Click "Connect" to add a new port.
            </div>

            <div class="form-row">
                <div class="form-group">
                    <label>Serial Port:</label>
                    <select id="serialPort" disabled>
                        <option value="">Select Port...</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Baud Rate:</label>
                    <select id="baudRate">
                        <option value="9600" selected>9600</option>
                        <option value="19200">19200</option>
                        <option value="38400">38400</option>
                        <option value="57600">57600</option>
                        <option value="115200">115200</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Data Bits:</label>
                    <select id="dataBits">
                        <option value="8" selected>8</option>
                        <option value="7">7</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Stop Bits:</label>
                    <select id="stopBits">
                        <option value="1" selected>1</option>
                        <option value="2">2</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Parity:</label>
                    <select id="parity">
                        <option value="none" selected>None</option>
                        <option value="even">Even</option>
                        <option value="odd">Odd</option>
                    </select>
                </div>
            </div>

            <div class="button-group">
                <button class="btn btn-primary" onclick="connectSerial()" id="connectBtn">Connect</button>
                <button class="btn btn-secondary" onclick="disconnectSerial()" id="disconnectBtn" disabled>Disconnect</button>
                <button class="btn btn-secondary" onclick="refreshPorts()">Refresh Ports</button>
            </div>

            <div class="form-group" style="margin-top: 20px;">
                <label>Test Frame Selection:</label>
                <select id="testFrameSelect" disabled>
                    <option value="">Select Test Frame...</option>
                    <option value="1">Frame 1: 2nd Harmonic, Point 0 (40%)</option>
                    <option value="2">Frame 2: 2nd Harmonic, Point 1 (5%)</option>
                    <option value="3">Frame 3: 2nd Harmonic, Point 2 (1%)</option>
                    <option value="4">Frame 4: 3rd Harmonic, Point 0 (40%)</option>
                    <option value="5">Frame 5: 3rd Harmonic, Point 1 (5%)</option>
                    <option value="6">Frame 6: 3rd Harmonic, Point 2 (1%)</option>
                    <option value="7">Frame 7: 5th Harmonic, Point 0 (40%)</option>
                    <option value="8">Frame 8: 5th Harmonic, Point 1 (5%)</option>
                    <option value="9">Frame 9: 5th Harmonic, Point 2 (1%)</option>
                    <option value="10">Frame 10: 11th Harmonic, Point 0 (40%)</option>
                    <option value="11">Frame 11: 11th Harmonic, Point 1 (5%)</option>
                    <option value="12">Frame 12: 11th Harmonic, Point 2 (1%)</option>
                    <option value="13">Frame 13: 21st Harmonic, Point 0 (40%)</option>
                    <option value="14">Frame 14: 21st Harmonic, Point 1 (5%)</option>
                    <option value="15">Frame 15: 21st Harmonic, Point 2 (1%)</option>
                    <option value="16">Frame 16: 31st Harmonic, Point 0 (40%)</option>
                    <option value="17">Frame 17: 31st Harmonic, Point 1 (5%)</option>
                    <option value="18">Frame 18: 31st Harmonic, Point 2 (1%)</option>
                    <option value="19">Frame 19: 41st Harmonic, Point 0 (40%)</option>
                    <option value="20">Frame 20: 41st Harmonic, Point 1 (5%)</option>
                    <option value="21">Frame 21: 41st Harmonic, Point 2 (1%)</option>
                </select>
            </div>

            <div class="button-group">
                <button class="btn btn-primary" onclick="sendTestFrame()" id="sendBtn" disabled>Send Frame</button>
                <button class="btn btn-secondary" onclick="sendAllFrames()" id="sendAllBtn" disabled>Send All Frames</button>
                <button class="btn btn-secondary" onclick="clearSerialLog()">Clear Log</button>
            </div>

            <div class="form-group" style="margin-top: 20px;">
                <label>Frame Delay (ms):</label>
                <input type="number" id="frameDelay" value="1000" min="100" max="10000" step="100">
                <small style="color: #666; font-size: 12px;">Delay between frames when sending all frames</small>
            </div>

            <div class="result-box" style="margin-top: 20px;">
                <div class="result-title">Serial Communication Log:</div>
                <div class="result-content" id="serialLog" style="max-height: 300px; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 12px;"></div>
            </div>
        </div>
    </div>

    <script>
        // Global variables to store parsed data
        let parsedProtocolType = '';
        let parsedData = {};
        let originalBytes = [];
        let serialPort = null;
        let writer = null;
        let reader = null;
        let isConnected = false;

        // Test frames data
        // Load test frames from external file
        let testFrames = [];
        let testFramesLoaded = false;
        
        async function loadTestFrames() {
            try {
                const response = await fetch('weston_harmonic_test_frames.txt');
                const text = await response.text();
                
                // Parse frames from text file
                const lines = text.split('\n');
                testFrames = [];
                
                for (const line of lines) {
                    if (line.trim().startsWith('FE FE FE FE')) {
                        testFrames.push(line.trim());
                    }
                }
                
                // Filter out response frames (only keep 81-byte frames)
                testFrames = testFrames.filter(frame => frame.split(' ').length === 81);
                
                testFramesLoaded = true;
                logMessage(`Loaded ${testFrames.length} test frames from file.`);
                
            } catch (error) {
                console.error('Failed to load test frames:', error);
                console.log('Using default test frames...');
                // Load default test frames
                testFrames = [
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 35 B4 4D 39 33 EB 5A 3C 33 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 33 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 33 DD 76 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 35 83 F6 34 34 EB 5A 3C 33 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 33 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 33 DD D0 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 35 83 F6 35 35 EB 5A 3C 33 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 33 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 33 DD D4 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 36 B4 4D 39 33 EB 5A 3C 34 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 34 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 34 DD 7A 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 36 83 F6 34 34 EB 5A 3C 34 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 34 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 34 DD D4 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 36 83 F6 35 35 EB 5A 3C 34 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 34 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 34 DD D8 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 38 B4 4D 39 33 EB 5A 3C 35 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 35 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 35 DD 7F 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 38 83 F6 34 34 EB 5A 3C 35 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 35 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 35 DD D9 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 38 83 F6 35 35 EB 5A 3C 35 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 35 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 35 DD DD 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 3E B4 4D 39 33 EB 5A 3C 36 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 36 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 36 DD 88 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 3E 83 F6 34 34 EB 5A 3C 36 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 36 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 36 DD E2 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 3E 83 F6 35 35 EB 5A 3C 36 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 36 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 36 DD E6 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 48 B4 4D 39 33 EB 5A 3C 37 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 37 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 37 DD 95 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 48 83 F6 34 34 EB 5A 3C 37 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 37 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 37 DD EF 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 48 83 F6 35 35 EB 5A 3C 37 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 37 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 37 DD F3 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 52 B4 4D 39 33 EB 5A 3C 38 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 38 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 38 DD A2 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 52 83 F6 34 34 EB 5A 3C 38 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 38 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 38 DD FC 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 52 83 F6 35 35 EB 5A 3C 38 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 38 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 38 DD 00 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 5C B4 4D 39 33 EB 5A 3C 39 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 39 DD 83 F6 33 33 B4 4D 39 33 EB 5A 3C 39 DD AF 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 5C 83 F6 34 34 EB 5A 3C 39 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 39 DD 83 F6 33 33 83 F6 34 33 EB 5A 3C 39 DD 09 16",
                    "FE FE FE FE 68 00 00 00 00 00 00 68 14 41 0E 12 12 37 35 33 33 33 37 36 35 34 35 39 12 0E BB BB BB BB DD 36 DD 32 32 DD 83 F6 33 5C 83 F6 35 35 EB 5A 3C 49 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 49 DD 83 F6 33 33 83 F6 35 33 EB 5A 3C 49 DD 3D 16"
                ];
                testFramesLoaded = true;
                console.log('Using default test frames (21 frames).');
            }
        }
        
        // Load test frames when page loads
        window.addEventListener('DOMContentLoaded', function() {
            loadTestFrames();
        });
        
        // Switch tabs
        function switchTab(tabName) {
            document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));
            document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
            
            event.target.classList.add('active');
            document.getElementById(tabName).classList.add('active');
        }

        // Show corresponding calibration form
        function showCalibrationForm() {
            const type = document.getElementById('calibrationType').value;
            document.querySelectorAll('.calibration-form').forEach(form => form.style.display = 'none');
            document.getElementById(type + 'Form').style.display = 'block';
        }

        // Add 33 to byte
        function add33(num) {
            return (num + 0x33) & 0xFF;
        }

        // Convert number to byte array (little endian)
        function numberToBytes(num, bytes, multiplier) {
            const value = Math.round(num * multiplier);
            const result = [];
            for (let i = 0; i < bytes; i++) {
                result.push((value >> (i * 8)) & 0xFF);
            }
            return result;
        }

        // Calculate checksum
        function calculateChecksum(data) {
            let sum = 0;
            for (let i = 0; i < data.length; i++) {
                sum += data[i];
            }
            return sum & 0xFF;
        }

        // Compose fundamental calibration frame
        function composeFundamental() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 34 (Fundamental calibration code)
            frame.push(0xDD, 0x34, 0xDD, 0x32, 0x32, 0xDD);
            
            // Phase A parameters
            const aVoltage = numberToBytes(parseFloat(document.getElementById('fundamentalAVoltage').value), 3, 10000);
            const aCurrent = numberToBytes(parseFloat(document.getElementById('fundamentalACurrent').value), 3, 100000);
            const aPhase = numberToBytes(parseFloat(document.getElementById('fundamentalAPhase').value), 3, 10000);
            
            frame.push(...aVoltage.map(add33));
            frame.push(0x34); // Fundamental order
            frame.push(...aCurrent.map(add33));
            
            const pointIndex = parseInt(document.getElementById('fundamentalPointIndex').value);
            frame.push(add33(pointIndex));
            
            frame.push(...aPhase.map(add33));
            
            const isLast = document.getElementById('fundamentalIsLast').checked;
            frame.push(add33(isLast ? 0x10 : 0x00));
            
            // Phase B parameters
            frame.push(0xDD);
            const bVoltage = numberToBytes(parseFloat(document.getElementById('fundamentalBVoltage').value), 3, 10000);
            const bCurrent = numberToBytes(parseFloat(document.getElementById('fundamentalBCurrent').value), 3, 100000);
            const bPhase = numberToBytes(parseFloat(document.getElementById('fundamentalBPhase').value), 3, 10000);
            
            frame.push(...bVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Phase C parameters
            frame.push(0xDD);
            const cVoltage = numberToBytes(parseFloat(document.getElementById('fundamentalCVoltage').value), 3, 10000);
            const cCurrent = numberToBytes(parseFloat(document.getElementById('fundamentalCCurrent').value), 3, 100000);
            const cPhase = numberToBytes(parseFloat(document.getElementById('fundamentalCPhase').value), 3, 10000);
            
            frame.push(...cVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Checksum
            frame.push(0xDD);
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose harmonic calibration frame
        function composeHarmonic() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 36 (Harmonic calibration code)
            frame.push(0xDD, 0x36, 0xDD, 0x32, 0x32, 0xDD);
            
            // Phase A parameters
            const aVoltage = numberToBytes(parseFloat(document.getElementById('harmonicAVoltage').value), 3, 10000);
            const aCurrent = numberToBytes(parseFloat(document.getElementById('harmonicACurrent').value), 3, 10000);
            const aPhase = numberToBytes(parseFloat(document.getElementById('harmonicAPhase').value), 3, 10000);
            
            const harmonicOrder = parseInt(document.getElementById('harmonicOrder').value);
            const pointIndex = parseInt(document.getElementById('harmonicPointIndex').value);
            const orderIndex = parseInt(document.getElementById('harmonicOrderIndex').value);
            const isLastPoint = document.getElementById('harmonicLastPoint').checked;
            
            frame.push(...aVoltage.map(add33));
            frame.push(add33(harmonicOrder));
            frame.push(...aCurrent.map(add33));
            frame.push(add33(pointIndex));
            frame.push(...aPhase.map(add33));
            
            // Byte 51: bit 4 = last point flag, bit 3-0 = harmonic order index
            // If last point: 0x10 + orderIndex, else: 0x00 + orderIndex
            const byte51 = isLastPoint ? (0x10 | orderIndex) : orderIndex;
            frame.push(add33(byte51));
            
            // Phase B parameters
            frame.push(0xDD);
            const bVoltage = numberToBytes(parseFloat(document.getElementById('harmonicBVoltage').value), 3, 10000);
            const bCurrent = numberToBytes(parseFloat(document.getElementById('harmonicBCurrent').value), 3, 10000);
            const bPhase = numberToBytes(parseFloat(document.getElementById('harmonicBPhase').value), 3, 10000);
            
            frame.push(...bVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Phase C parameters
            frame.push(0xDD);
            const cVoltage = numberToBytes(parseFloat(document.getElementById('harmonicCVoltage').value), 3, 10000);
            const cCurrent = numberToBytes(parseFloat(document.getElementById('harmonicCCurrent').value), 3, 10000);
            const cPhase = numberToBytes(parseFloat(document.getElementById('harmonicCPhase').value), 3, 10000);
            
            frame.push(...cVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Checksum
            frame.push(0xDD);
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose pulse constant frame
        function composePulse() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 37 (Function code)
            frame.push(0xDD, 0x37, 0xDD, 0x32, 0x32, 0xDD, 0x32, 0x32, 0x32, 0x32, 0x34, 0x33, 0x33, 0x33);
            
            const wireMode = parseInt(document.getElementById('wireMode').value);
            frame.push(add33(wireMode));
            frame.push(0x33, 0x33, 0x33, 0xDD);
            
            const fundamentalPulse = numberToBytes(parseInt(document.getElementById('fundamentalPulseConstant').value), 4, 1);
            const harmonicPulse = numberToBytes(parseInt(document.getElementById('harmonicPulseConstant').value), 4, 1);
            
            frame.push(...fundamentalPulse.map(add33));
            frame.push(...harmonicPulse.map(add33));
            frame.push(0x33, 0x33, 0x33, 0x33, 0xDD);
            frame.push(0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xDD);
            
            // Checksum
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose harmonic count frame
        function composeHarmonicCount() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 37 (Function code)
            frame.push(0xDD, 0x37, 0xDD, 0x32, 0x32, 0xDD, 0x32, 0x32, 0x32, 0x32, 0x43, 0x33, 0x33, 0x33);
            
            const harmonicOrder = parseInt(document.getElementById('currentHarmonicOrder').value);
            const orderIndex = parseInt(document.getElementById('currentHarmonicOrderIndex').value);
            
            frame.push(0x33); // Reserved
            frame.push(add33(harmonicOrder));
            frame.push(add33(orderIndex));
            frame.push(0x33, 0xDD);
            frame.push(0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xDD);
            
            // Checksum
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose calibration preparation frame
        function composePreparation() {
            const frame = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x15, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x34, 0x35, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose calibration parameter initialization frame
        function composeInit() {
            const frame = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB, 0xDD, 0x32, 
                           0xDD, 0x32, 0x32, 0xDD, 0x32, 0x32, 0x32, 0x32, 0x34, 0x33, 0x33, 0x33, 
                           0x33, 0x33, 0x33, 0x33, 0xDD, 0x53, 0x81, 0x33, 0x33, 0x73, 0x40, 0x36, 
                           0x33, 0x33, 0x33, 0x33, 0x33, 0xDD, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 
                           0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xDD];
            
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Main compose function
        function composeFrame() {
            const type = document.getElementById('calibrationType').value;
            let frame;
            
            switch(type) {
                case 'preparation':
                    frame = composePreparation();
                    break;
                case 'init':
                    frame = composeInit();
                    break;
                case 'fundamental':
                    frame = composeFundamental();
                    break;
                case 'harmonic':
                    frame = composeHarmonic();
                    break;
                case 'pulse':
                    frame = composePulse();
                    break;
                case 'harmonicCount':
                    frame = composeHarmonicCount();
                    break;
            }
            
            const hexFrame = frame.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ');
            document.getElementById('composeResultContent').textContent = hexFrame;
            document.getElementById('composeResult').style.display = 'block';
        }

        // Subtract 33 from byte
        function sub33(num) {
            return (num - 0x33) & 0xFF;
        }

        // Convert byte array to number (little endian)
        function bytesToNumber(bytes, multiplier) {
            let value = 0;
            for (let i = 0; i < bytes.length; i++) {
                value |= (bytes[i] << (i * 8));
            }
            return value / multiplier;
        }

        // Parse protocol frame
        function parseFrame() {
            const input = document.getElementById('parseInput').value.trim();
            if (!input) {
                alert('Please enter protocol frame');
                return;
            }
            
            const bytes = input.split(/\s+/).map(s => parseInt(s, 16));
            originalBytes = [...bytes]; // Store original bytes
            
            if (bytes.length < 10) {
                alert('Protocol frame length insufficient');
                return;
            }
            
            // Find the second 0x68 (actual frame start after FE FE FE FE 68 XX XX XX XX XX XX)
            let first68 = bytes.indexOf(0x68);
            let second68 = bytes.indexOf(0x68, first68 + 1);
            
            if (second68 === -1) {
                // Only one 0x68 found, use it as frame start
                second68 = first68;
            }
            
            let result = '<div class="parsed-item"><span class="parsed-label">Protocol Type:</span>';
            
            // Standard frame structure: 
            // FE FE FE FE 68 00 00 00 00 00 00 68 14/15 ... (with prefix)
            //          68 00 00 00 00 00 00 68 14/15 ... (without prefix)
            // Second 68 is at position 11 (with prefix) or 7 (without prefix)
            // After second 68, next byte is at position 12 (0x14) with prefix
            
            // Find where code14 (0x14 or 0x15) is located
            const code14Index = second68 + 1;  // One byte after second 68
            const code14 = bytes[code14Index];
            
            // The next byte should be 0x41 (for most commands except preparation)
            const code41 = bytes[code14Index + 1];
            
            // Byte 35 in standard frame is the function code after DD separator
            // Structure: ... BB DD CODE ...
            // Find the first DD after second 68
            let ddIndex = -1;
            for (let i = second68 + 1; i < bytes.length; i++) {
                if (bytes[i] === 0xDD) {
                    ddIndex = i;
                    break;
                }
            }
            
            const code35 = (ddIndex !== -1 && ddIndex + 1 < bytes.length) ? bytes[ddIndex + 1] : 0xFF;
            
            let parsedData = '';
            
            // Check calibration preparation (byte at position 15 should be 0x15)
            if (code14 === 0x14 && code41 === 0x15) {
                result += 'Calibration Preparation</div>';
                parsedProtocolType = 'preparation';
                parsedData = parseCalibrationPreparation(bytes);
            }
            // Check calibration parameter initialization
            else if (code14 === 0x14 && code41 === 0x41 && code35 === 0x32) {
                result += 'Calibration Parameter Initialization</div>';
                parsedProtocolType = 'init';
                parsedData = parseCalibrationInit(bytes);
            }
            // Check fundamental calibration
            else if (code14 === 0x14 && code41 === 0x41 && code35 === 0x34) {
                result += 'Fundamental Calibration</div>';
                parsedProtocolType = 'fundamental';
                parsedData = parseFundamental(bytes);
            }
            // Check harmonic calibration
            else if (code14 === 0x14 && code41 === 0x41 && code35 === 0x36) {
                result += 'Harmonic Calibration</div>';
                parsedProtocolType = 'harmonic';
                parsedData = parseHarmonic(bytes);
            }
            // Check pulse constant or harmonic count
            else if (code14 === 0x14 && code41 === 0x41 && code35 === 0x37) {
                // Find the byte at index 44 (after BB BB BB BB DD 37 DD 32 32 DD 32 32 32 32...)
                let byte44Index = ddIndex + 2;  // After DD CODE, find index 44
                if (ddIndex !== -1) {
                    // Count bytes from second 68
                    // Standard: BB BB BB BB = 4 bytes, then DD = 1 byte at position 35
                    // So position 44 is at ddIndex + (44-35) = ddIndex + 9
                    byte44Index = ddIndex + 9;
                }
                const byte44 = (byte44Index < bytes.length) ? bytes[byte44Index] : 0x00;
                
                if (byte44 === 0x43) {
                    result += 'Set Harmonic Order</div>';
                    parsedProtocolType = 'harmonicCount';
                    parsedData = parseHarmonicCount(bytes);
                } else {
                    result += 'Set Pulse Constant</div>';
                    parsedProtocolType = 'pulse';
                    parsedData = parsePulse(bytes);
                }
            } else {
                result += 'Unknown Type</div>';
                parsedProtocolType = 'unknown';
                parsedData = `<div class="parsed-item"><span class="parsed-label">Debug Info:</span>code14=0x${code14.toString(16)}, code41=0x${code41.toString(16)}, code35=0x${code35.toString(16)}, ddIndex=${ddIndex}</div>`;
            }
            
            // Store parsed data and show editable form directly
            document.getElementById('parseResult').style.display = 'none';
            showEditableForm();
            
            // Hide compose result section for read-only protocols
            if (parsedProtocolType === 'preparation' || parsedProtocolType === 'init') {
                document.getElementById('composeFromParseResult').style.display = 'none';
            }
        }

        // Parse fundamental calibration
        function parseFundamental(bytes) {
            let html = '';
            
            const aVoltBytes = bytes.slice(40, 43).map(sub33);
            const aCurrBytes = bytes.slice(44, 47).map(sub33);
            const aPhaseBytes = bytes.slice(48, 51).map(sub33);
            const pointIndex = sub33(bytes[47]);
            const isLast = sub33(bytes[51]) === 0x10;
            
            // Store parsed data for editing
            parsedData = {
                pointIndex: pointIndex,
                isLast: isLast,
                aVoltage: bytesToNumber(aVoltBytes, 10000),
                aCurrent: bytesToNumber(aCurrBytes, 100000),
                aPhase: bytesToNumber(aPhaseBytes, 10000),
                bVoltage: bytesToNumber(bytes.slice(53, 56).map(sub33), 10000),
                bCurrent: bytesToNumber(bytes.slice(57, 60).map(sub33), 100000),
                bPhase: bytesToNumber(bytes.slice(61, 64).map(sub33), 10000),
                cVoltage: bytesToNumber(bytes.slice(66, 69).map(sub33), 10000),
                cCurrent: bytesToNumber(bytes.slice(70, 73).map(sub33), 100000),
                cPhase: bytesToNumber(bytes.slice(74, 77).map(sub33), 10000)
            };
            
            html += `<div class="parsed-item"><span class="parsed-label">Calibration Point Index:</span>${pointIndex}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Is Last Point:</span>${isLast ? 'Yes' : 'No'}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase A Voltage:</span>${parsedData.aVoltage.toFixed(4)}V</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase A Current:</span>${parsedData.aCurrent.toFixed(5)}A</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase A Phase:</span>${parsedData.aPhase.toFixed(4)}deg</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase B Voltage:</span>${parsedData.bVoltage.toFixed(4)}V</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase B Current:</span>${parsedData.bCurrent.toFixed(5)}A</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase B Phase:</span>${parsedData.bPhase.toFixed(4)}deg</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase C Voltage:</span>${parsedData.cVoltage.toFixed(4)}V</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase C Current:</span>${parsedData.cCurrent.toFixed(5)}A</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase C Phase:</span>${parsedData.cPhase.toFixed(4)}deg</div>`;
            
            return html;
        }

        // Parse harmonic calibration
        function parseHarmonic(bytes) {
            let html = '';
            
            const aVoltBytes = bytes.slice(40, 43).map(sub33);
            const harmonicOrder = sub33(bytes[43]);
            const aCurrBytes = bytes.slice(44, 47).map(sub33);
            const pointIndex = sub33(bytes[47]);
            const aPhaseBytes = bytes.slice(48, 51).map(sub33);
            
            // Parse byte 51: bit 4 = last point flag, bit 3-0 = harmonic order index
            const byte51 = sub33(bytes[51]);
            const isLastPoint = (byte51 & 0x10) !== 0;
            const orderIndex = byte51 & 0x0F;
            
            // Store parsed data for editing
            parsedData = {
                harmonicOrder: harmonicOrder,
                pointIndex: pointIndex,
                orderIndex: orderIndex,
                isLastPoint: isLastPoint,
                aVoltage: bytesToNumber(aVoltBytes, 10000),
                aCurrent: bytesToNumber(aCurrBytes, 10000),
                aPhase: bytesToNumber(aPhaseBytes, 10000),
                bVoltage: bytesToNumber(bytes.slice(53, 56).map(sub33), 10000),
                bCurrent: bytesToNumber(bytes.slice(57, 60).map(sub33), 10000),
                bPhase: bytesToNumber(bytes.slice(61, 64).map(sub33), 10000),
                cVoltage: bytesToNumber(bytes.slice(66, 69).map(sub33), 10000),
                cCurrent: bytesToNumber(bytes.slice(70, 73).map(sub33), 10000),
                cPhase: bytesToNumber(bytes.slice(74, 77).map(sub33), 10000)
            };
            
            html += `<div class="parsed-item"><span class="parsed-label">Harmonic Order:</span>${harmonicOrder}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Calibration Point Index:</span>${pointIndex}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Harmonic Order Index:</span>${orderIndex}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Last Calibration Point (Entire Process):</span>${isLastPoint ? 'Yes' : 'No'}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase A Harmonic Voltage:</span>${parsedData.aVoltage.toFixed(4)}%</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase A Harmonic Current:</span>${parsedData.aCurrent.toFixed(4)}%</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase A Phase:</span>${parsedData.aPhase.toFixed(4)}deg</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase B Harmonic Voltage:</span>${parsedData.bVoltage.toFixed(4)}%</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase B Harmonic Current:</span>${parsedData.bCurrent.toFixed(4)}%</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase B Phase:</span>${parsedData.bPhase.toFixed(4)}deg</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase C Harmonic Voltage:</span>${parsedData.cVoltage.toFixed(4)}%</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase C Harmonic Current:</span>${parsedData.cCurrent.toFixed(4)}%</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Phase C Phase:</span>${parsedData.cPhase.toFixed(4)}deg</div>`;
            
            return html;
        }

        // Parse pulse constant
        function parsePulse(bytes) {
            let html = '';
            
            const wireMode = sub33(bytes[48]);
            const fundamentalPulseBytes = bytes.slice(53, 57).map(sub33);
            const harmonicPulseBytes = bytes.slice(57, 61).map(sub33);
            
            // Store parsed data for editing
            parsedData = {
                wireMode: wireMode,
                fundamentalPulseConstant: bytesToNumber(fundamentalPulseBytes, 1),
                harmonicPulseConstant: bytesToNumber(harmonicPulseBytes, 1)
            };
            
            html += `<div class="parsed-item"><span class="parsed-label">Wiring Mode:</span>${wireMode === 3 ? '3-Phase 3-Wire' : '3-Phase 4-Wire'}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Fundamental Pulse Constant:</span>${parsedData.fundamentalPulseConstant}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Harmonic Pulse Constant:</span>${parsedData.harmonicPulseConstant}</div>`;
            
            return html;
        }

        // Parse harmonic count
        function parseHarmonicCount(bytes) {
            let html = '';
            
            const harmonicOrder = sub33(bytes[49]);
            const orderIndex = sub33(bytes[50]);
            
            // Store parsed data for editing
            parsedData = {
                harmonicOrder: harmonicOrder,
                orderIndex: orderIndex
            };
            
            html += `<div class="parsed-item"><span class="parsed-label">Current Harmonic Order:</span>${harmonicOrder}</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Harmonic Order Index:</span>${orderIndex}</div>`;
            
            return html;
        }

        // Parse calibration preparation
        function parseCalibrationPreparation(bytes) {
            let html = '';
            
            html += `<div class="parsed-item"><span class="parsed-label">Command:</span>Calibration Preparation</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Purpose:</span>Start calibration preparation</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Frame Length:</span>${bytes.length} bytes</div>`;
            
            return html;
        }

        // Parse calibration parameter initialization
        function parseCalibrationInit(bytes) {
            let html = '';
            
            html += `<div class="parsed-item"><span class="parsed-label">Command:</span>Calibration Parameter Initialization</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Note:</span>This command initializes calibration parameters</div>`;
            html += `<div class="parsed-item"><span class="parsed-label">Frame Length:</span>${bytes.length} bytes</div>`;
            
            return html;
        }

        // Clear compose form
        function clearComposeForm() {
            document.getElementById('composeResult').style.display = 'none';
        }

        // Clear parse form
        function clearParseForm() {
            document.getElementById('parseInput').value = '';
            document.getElementById('parseResult').style.display = 'none';
            document.getElementById('editableForm').style.display = 'none';
            document.getElementById('composeFromParseResult').style.display = 'none';
        }

        // Show editable form based on parsed data
        function showEditableForm() {
            if (parsedProtocolType === 'unknown') {
                alert('Cannot edit unknown protocol type');
                return;
            }
            
            let formHtml = '';
            let protocolTypeName = '';
            
            switch(parsedProtocolType) {
                case 'fundamental':
                    protocolTypeName = 'Fundamental Calibration';
                    formHtml = generateFundamentalEditableForm();
                    break;
                case 'harmonic':
                    protocolTypeName = 'Harmonic Calibration';
                    formHtml = generateHarmonicEditableForm();
                    break;
                case 'pulse':
                    protocolTypeName = 'Set Pulse Constant';
                    formHtml = generatePulseEditableForm();
                    break;
                case 'harmonicCount':
                    protocolTypeName = 'Set Harmonic Order';
                    formHtml = generateHarmonicCountEditableForm();
                    break;
                case 'preparation':
                    protocolTypeName = 'Calibration Preparation';
                    formHtml = generatePreparationReadOnlyForm();
                    break;
                case 'init':
                    protocolTypeName = 'Calibration Parameter Initialization';
                    formHtml = generateInitReadOnlyForm();
                    break;
            }
            
            // Add protocol type info at the top
            formHtml = `<div class="parsed-item" style="margin-bottom: 20px;"><span class="parsed-label">Protocol Type:</span>${protocolTypeName}</div>` + formHtml;
            
            // Add compose button for editable protocols, disabled button for read-only protocols
            if (parsedProtocolType === 'preparation' || parsedProtocolType === 'init') {
                formHtml += `
                    <div class="form-group">
                        <button type="button" onclick="composeFromParsed()" class="btn btn-primary" disabled style="opacity: 0.5; cursor: not-allowed;">
                            Compose New Frame (Read-Only)
                        </button>
                        <small style="color: #666; display: block; margin-top: 5px;">
                            This protocol type cannot be modified
                        </small>
                    </div>
                `;
            } else {
                formHtml += `
                    <div class="form-group">
                        <button type="button" onclick="composeFromParsed()" class="btn btn-primary">
                            Compose New Frame
                        </button>
                    </div>
                `;
            }
            
            document.getElementById('editableFormContent').innerHTML = formHtml;
            document.getElementById('editableForm').style.display = 'block';
        }

        // Generate editable form for fundamental calibration
        function generateFundamentalEditableForm() {
            return `
                <div class="form-group">
                    <label>Calibration Point Index (0~4):</label>
                    <input type="number" id="editPointIndex" min="0" max="4" value="${parsedData.pointIndex}">
                </div>
                <div class="form-group">
                    <label class="checkbox-group">
                        <input type="checkbox" id="editIsLast" ${parsedData.isLast ? 'checked' : ''}> Is Last Calibration Point
                    </label>
                </div>
                <div class="phase-section">
                    <div class="phase-title">Phase A Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase A Voltage (V):</label>
                            <input type="number" id="editAVoltage" step="0.0001" value="${parsedData.aVoltage}">
                        </div>
                        <div class="form-group">
                            <label>Phase A Current (A):</label>
                            <input type="number" id="editACurrent" step="0.00001" value="${parsedData.aCurrent}">
                        </div>
                        <div class="form-group">
                            <label>Phase A Phase (deg):</label>
                            <input type="number" id="editAPhase" step="0.0001" value="${parsedData.aPhase}">
                        </div>
                    </div>
                </div>
                <div class="phase-section">
                    <div class="phase-title">Phase B Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase B Voltage (V):</label>
                            <input type="number" id="editBVoltage" step="0.0001" value="${parsedData.bVoltage}">
                        </div>
                        <div class="form-group">
                            <label>Phase B Current (A):</label>
                            <input type="number" id="editBCurrent" step="0.00001" value="${parsedData.bCurrent}">
                        </div>
                        <div class="form-group">
                            <label>Phase B Phase (deg):</label>
                            <input type="number" id="editBPhase" step="0.0001" value="${parsedData.bPhase}">
                        </div>
                    </div>
                </div>
                <div class="phase-section">
                    <div class="phase-title">Phase C Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase C Voltage (V):</label>
                            <input type="number" id="editCVoltage" step="0.0001" value="${parsedData.cVoltage}">
                        </div>
                        <div class="form-group">
                            <label>Phase C Current (A):</label>
                            <input type="number" id="editCCurrent" step="0.00001" value="${parsedData.cCurrent}">
                        </div>
                        <div class="form-group">
                            <label>Phase C Phase (deg):</label>
                            <input type="number" id="editCPhase" step="0.0001" value="${parsedData.cPhase}">
                        </div>
                    </div>
                </div>
            `;
        }

        // Generate editable form for harmonic calibration
        function generateHarmonicEditableForm() {
            const harmonicOrderOptions = [
                {value: 2, text: '2nd Harmonic'},
                {value: 3, text: '3rd Harmonic'},
                {value: 5, text: '5th Harmonic'},
                {value: 11, text: '11th Harmonic'},
                {value: 21, text: '21st Harmonic'},
                {value: 31, text: '31st Harmonic'},
                {value: 41, text: '41st Harmonic'}
            ];
            const harmonicOrderSelect = harmonicOrderOptions.map(order => 
                `<option value="${order.value}" ${parsedData.harmonicOrder === order.value ? 'selected' : ''}>${order.text}</option>`
            ).join('');
            
            return `
                <div class="form-group">
                    <label>Harmonic Order:</label>
                    <select id="editHarmonicOrder">
                        ${harmonicOrderSelect}
                    </select>
                </div>
                <div class="form-group">
                    <label>Calibration Point Index (0~2):</label>
                    <input type="number" id="editPointIndex" min="0" max="2" value="${parsedData.pointIndex}">
                    <small style="color: #666; font-size: 12px;">0=40%, 1=5%, 2=1% (harmonic current content from high to low)</small>
                </div>
                <div class="form-group">
                    <label>Harmonic Order Index (0~6):</label>
                    <input type="number" id="editOrderIndex" min="0" max="6" value="${parsedData.orderIndex}">
                    <small style="color: #666; font-size: 12px;">0=2nd, 1=3rd, 2=5th, 3=11th, 4=21st, 5=31st, 6=41st</small>
                </div>
                <div class="form-group">
                    <label>
                        <input type="checkbox" id="editLastPoint" ${parsedData.isLastPoint ? 'checked' : ''} style="width: auto; margin-right: 8px;">
                        Last Calibration Point (Entire Process)
                    </label>
                    <small style="color: #666; font-size: 12px; display: block; margin-top: 5px;">
                        Check this ONLY if this is the very last calibration point of the entire harmonic calibration process (Frame 21)
                    </small>
                </div>
                <div class="phase-section">
                    <div class="phase-title">Phase A Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase A Harmonic Voltage (%)</label>
                            <input type="number" id="editAVoltage" step="0.0001" value="${parsedData.aVoltage}">
                        </div>
                        <div class="form-group">
                            <label>Phase A Harmonic Current (%)</label>
                            <input type="number" id="editACurrent" step="0.0001" value="${parsedData.aCurrent}">
                        </div>
                        <div class="form-group">
                            <label>Phase A Phase (deg):</label>
                            <input type="number" id="editAPhase" step="0.0001" value="${parsedData.aPhase}">
                        </div>
                    </div>
                </div>
                <div class="phase-section">
                    <div class="phase-title">Phase B Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase B Harmonic Voltage (%)</label>
                            <input type="number" id="editBVoltage" step="0.0001" value="${parsedData.bVoltage}">
                        </div>
                        <div class="form-group">
                            <label>Phase B Harmonic Current (%)</label>
                            <input type="number" id="editBCurrent" step="0.0001" value="${parsedData.bCurrent}">
                        </div>
                        <div class="form-group">
                            <label>Phase B Phase (deg):</label>
                            <input type="number" id="editBPhase" step="0.0001" value="${parsedData.bPhase}">
                        </div>
                    </div>
                </div>
                <div class="phase-section">
                    <div class="phase-title">Phase C Parameters</div>
                    <div class="form-row">
                        <div class="form-group">
                            <label>Phase C Harmonic Voltage (%)</label>
                            <input type="number" id="editCVoltage" step="0.0001" value="${parsedData.cVoltage}">
                        </div>
                        <div class="form-group">
                            <label>Phase C Harmonic Current (%)</label>
                            <input type="number" id="editCCurrent" step="0.0001" value="${parsedData.cCurrent}">
                        </div>
                        <div class="form-group">
                            <label>Phase C Phase (deg):</label>
                            <input type="number" id="editCPhase" step="0.0001" value="${parsedData.cPhase}">
                        </div>
                    </div>
                </div>
            `;
        }

        // Generate editable form for pulse constant
        function generatePulseEditableForm() {
            return `
                <div class="form-group">
                    <label>Wiring Mode:</label>
                    <select id="editWireMode">
                        <option value="3" ${parsedData.wireMode === 3 ? 'selected' : ''}>3-Phase 3-Wire</option>
                        <option value="4" ${parsedData.wireMode === 4 ? 'selected' : ''}>3-Phase 4-Wire</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Fundamental Pulse Constant:</label>
                    <input type="number" id="editFundamentalPulseConstant" value="${parsedData.fundamentalPulseConstant}">
                </div>
                <div class="form-group">
                    <label>Harmonic Pulse Constant:</label>
                    <input type="number" id="editHarmonicPulseConstant" value="${parsedData.harmonicPulseConstant}">
                </div>
            `;
        }

        // Generate read-only form for calibration preparation
        function generatePreparationReadOnlyForm() {
            const bytes = originalBytes;
            const dataStart = 10; // After 68 00 00 00 00 00 00 68 14 15
            
            let formHtml = `
                <div class="readonly-notice">
                    <div class="notice-icon">??</div>
                    <div class="notice-text">
                        <strong>This protocol type cannot be edited (no parameters)</strong>
                        <br><small>Calibration Preparation frames are read-only and cannot be modified.</small>
                    </div>
                </div>
                
                <div class="form-group readonly-group">
                    <label>Protocol Information:</label>
                    <div class="readonly-info">
                        <div class="info-item">
                            <span class="info-label">Command:</span>
                            <span class="info-value">Calibration Preparation</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Purpose:</span>
                            <span class="info-value">Start calibration preparation</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Frame Length:</span>
                            <span class="info-value">${bytes.length} bytes</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Data Section:</span>
                            <span class="info-value">${bytes.slice(dataStart, dataStart + 16).map(b => '0x' + b.toString(16).toUpperCase()).join(' ')}</span>
                        </div>
                    </div>
                </div>
                
                <div class="form-group readonly-group">
                    <label>Frame Analysis:</label>
                    <div class="readonly-info">
                        <div class="info-item">
                            <span class="info-label">Parameter 1:</span>
                            <span class="info-value">0x${bytes[dataStart].toString(16).toUpperCase()}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Parameter 2:</span>
                            <span class="info-value">0x${bytes[dataStart + 1].toString(16).toUpperCase()}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Parameter 3:</span>
                            <span class="info-value">0x${bytes[dataStart + 2].toString(16).toUpperCase()}</span>
                        </div>
                    </div>
                </div>
            `;
            
            return formHtml;
        }

        // Generate read-only form for calibration parameter initialization
        function generateInitReadOnlyForm() {
            const bytes = originalBytes;
            const dataStart = 10; // After 68 00 00 00 00 00 00 68 14 41
            
            let formHtml = `
                <div class="readonly-notice">
                    <div class="notice-icon">??</div>
                    <div class="notice-text">
                        <strong>This protocol type cannot be edited (no parameters)</strong>
                        <br><small>Calibration Parameter Initialization frames are read-only and cannot be modified.</small>
                    </div>
                </div>
                
                <div class="form-group readonly-group">
                    <label>Protocol Information:</label>
                    <div class="readonly-info">
                        <div class="info-item">
                            <span class="info-label">Command:</span>
                            <span class="info-value">Calibration Parameter Initialization</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Purpose:</span>
                            <span class="info-value">Initialize calibration parameters</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Frame Length:</span>
                            <span class="info-value">${bytes.length} bytes</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Data Section:</span>
                            <span class="info-value">${bytes.slice(dataStart, Math.min(dataStart + 20, bytes.length - 2)).map(b => '0x' + b.toString(16).toUpperCase().padStart(2, '0')).join(' ')}${bytes.length > dataStart + 20 ? '...' : ''}</span>
                        </div>
                    </div>
                </div>
                
                <div class="form-group readonly-group">
                    <label>Frame Structure:</label>
                    <div class="readonly-info">
                        <div class="info-item">
                            <span class="info-label">Start Bytes:</span>
                            <span class="info-value">0x${bytes[0].toString(16).toUpperCase().padStart(2, '0')} 0x${bytes[1].toString(16).toUpperCase().padStart(2, '0')} 0x${bytes[2].toString(16).toUpperCase().padStart(2, '0')} 0x${bytes[3].toString(16).toUpperCase().padStart(2, '0')}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Frame Header:</span>
                            <span class="info-value">0x${bytes[4].toString(16).toUpperCase().padStart(2, '0')} ... 0x${bytes[13].toString(16).toUpperCase().padStart(2, '0')}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Command Code:</span>
                            <span class="info-value">0x${bytes[13].toString(16).toUpperCase().padStart(2, '0')} 0x${bytes[14].toString(16).toUpperCase().padStart(2, '0')}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">Checksum:</span>
                            <span class="info-value">0x${bytes[bytes.length - 2].toString(16).toUpperCase().padStart(2, '0')}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">End Byte:</span>
                            <span class="info-value">0x${bytes[bytes.length - 1].toString(16).toUpperCase().padStart(2, '0')}</span>
                        </div>
                    </div>
                </div>
            `;
            
            return formHtml;
        }

        // Generate editable form for harmonic count
        function generateHarmonicCountEditableForm() {
            const harmonicOrderOptions = [
                {value: 2, text: '2nd Harmonic'},
                {value: 3, text: '3rd Harmonic'},
                {value: 5, text: '5th Harmonic'},
                {value: 11, text: '11th Harmonic'},
                {value: 21, text: '21st Harmonic'},
                {value: 31, text: '31st Harmonic'},
                {value: 41, text: '41st Harmonic'}
            ];
            const harmonicOrderSelect = harmonicOrderOptions.map(order => 
                `<option value="${order.value}" ${parsedData.harmonicOrder === order.value ? 'selected' : ''}>${order.text}</option>`
            ).join('');
            
            return `
                <div class="form-group">
                    <label>Current Harmonic Order:</label>
                    <select id="editCurrentHarmonicOrder">
                        ${harmonicOrderSelect}
                    </select>
                </div>
                <div class="form-group">
                    <label>Harmonic Order Index (0~6):</label>
                    <input type="number" id="editCurrentHarmonicOrderIndex" min="0" max="6" value="${parsedData.orderIndex}">
                    <small style="color: #666; font-size: 12px;">0=2nd, 1=3rd, 2=5th, 3=11th, 4=21st, 5=31st, 6=41st</small>
                </div>
            `;
        }

        // Hide editable form
        function hideEditableForm() {
            document.getElementById('editableForm').style.display = 'none';
        }

        // Compose frame from parsed data
        function composeFromParsed() {
            // Check if this is a read-only protocol type
            if (parsedProtocolType === 'preparation' || parsedProtocolType === 'init') {
                alert('This protocol type cannot be modified (read-only)');
                return;
            }
            
            let frame;
            
            switch(parsedProtocolType) {
                case 'fundamental':
                    frame = composeFundamentalFromParsed();
                    break;
                case 'harmonic':
                    frame = composeHarmonicFromParsed();
                    break;
                case 'pulse':
                    frame = composePulseFromParsed();
                    break;
                case 'harmonicCount':
                    frame = composeHarmonicCountFromParsed();
                    break;
                default:
                    alert('Cannot compose frame for this protocol type');
                    return;
            }
            
            const hexFrame = frame.map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ');
            document.getElementById('composeFromParseResultContent').textContent = hexFrame;
            document.getElementById('composeFromParseResult').style.display = 'block';
        }

        // Compose fundamental calibration from parsed data
        function composeFundamentalFromParsed() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 34 (Fundamental calibration code)
            frame.push(0xDD, 0x34, 0xDD, 0x32, 0x32, 0xDD);
            
            // Phase A parameters
            const aVoltage = numberToBytes(parseFloat(document.getElementById('editAVoltage').value), 3, 10000);
            const aCurrent = numberToBytes(parseFloat(document.getElementById('editACurrent').value), 3, 100000);
            const aPhase = numberToBytes(parseFloat(document.getElementById('editAPhase').value), 3, 10000);
            
            frame.push(...aVoltage.map(add33));
            frame.push(0x34); // Fundamental order
            frame.push(...aCurrent.map(add33));
            
            const pointIndex = parseInt(document.getElementById('editPointIndex').value);
            frame.push(add33(pointIndex));
            
            frame.push(...aPhase.map(add33));
            
            const isLast = document.getElementById('editIsLast').checked;
            frame.push(add33(isLast ? 0x10 : 0x00));
            
            // Phase B parameters
            frame.push(0xDD);
            const bVoltage = numberToBytes(parseFloat(document.getElementById('editBVoltage').value), 3, 10000);
            const bCurrent = numberToBytes(parseFloat(document.getElementById('editBCurrent').value), 3, 100000);
            const bPhase = numberToBytes(parseFloat(document.getElementById('editBPhase').value), 3, 10000);
            
            frame.push(...bVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Phase C parameters
            frame.push(0xDD);
            const cVoltage = numberToBytes(parseFloat(document.getElementById('editCVoltage').value), 3, 10000);
            const cCurrent = numberToBytes(parseFloat(document.getElementById('editCCurrent').value), 3, 100000);
            const cPhase = numberToBytes(parseFloat(document.getElementById('editCPhase').value), 3, 10000);
            
            frame.push(...cVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Checksum
            frame.push(0xDD);
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose harmonic calibration from parsed data
        function composeHarmonicFromParsed() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 36 (Harmonic calibration code)
            frame.push(0xDD, 0x36, 0xDD, 0x32, 0x32, 0xDD);
            
            // Phase A parameters
            const aVoltage = numberToBytes(parseFloat(document.getElementById('editAVoltage').value), 3, 10000);
            const aCurrent = numberToBytes(parseFloat(document.getElementById('editACurrent').value), 3, 10000);
            const aPhase = numberToBytes(parseFloat(document.getElementById('editAPhase').value), 3, 10000);
            
            const harmonicOrder = parseInt(document.getElementById('editHarmonicOrder').value);
            const pointIndex = parseInt(document.getElementById('editPointIndex').value);
            const orderIndex = parseInt(document.getElementById('editOrderIndex').value);
            const isLastPoint = document.getElementById('editLastPoint') ? document.getElementById('editLastPoint').checked : false;
            
            frame.push(...aVoltage.map(add33));
            frame.push(add33(harmonicOrder));
            frame.push(...aCurrent.map(add33));
            frame.push(add33(pointIndex));
            frame.push(...aPhase.map(add33));
            
            // Byte 51: bit 4 = last point flag, bit 3-0 = harmonic order index
            // If last point: 0x10 + orderIndex, else: 0x00 + orderIndex
            const byte51 = isLastPoint ? (0x10 | orderIndex) : orderIndex;
            frame.push(add33(byte51));
            
            // Phase B parameters
            frame.push(0xDD);
            const bVoltage = numberToBytes(parseFloat(document.getElementById('editBVoltage').value), 3, 10000);
            const bCurrent = numberToBytes(parseFloat(document.getElementById('editBCurrent').value), 3, 10000);
            const bPhase = numberToBytes(parseFloat(document.getElementById('editBPhase').value), 3, 10000);
            
            frame.push(...bVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...bPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Phase C parameters
            frame.push(0xDD);
            const cVoltage = numberToBytes(parseFloat(document.getElementById('editCVoltage').value), 3, 10000);
            const cCurrent = numberToBytes(parseFloat(document.getElementById('editCCurrent').value), 3, 10000);
            const cPhase = numberToBytes(parseFloat(document.getElementById('editCPhase').value), 3, 10000);
            
            frame.push(...cVoltage.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cCurrent.map(add33));
            frame.push(0x33); // Reserved
            frame.push(...cPhase.map(add33));
            frame.push(0x33); // Reserved
            
            // Checksum
            frame.push(0xDD);
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose pulse constant from parsed data
        function composePulseFromParsed() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 37 (Function code)
            frame.push(0xDD, 0x37, 0xDD, 0x32, 0x32, 0xDD, 0x32, 0x32, 0x32, 0x32, 0x34, 0x33, 0x33, 0x33);
            
            const wireMode = parseInt(document.getElementById('editWireMode').value);
            frame.push(add33(wireMode));
            frame.push(0x33, 0x33, 0x33, 0xDD);
            
            const fundamentalPulse = numberToBytes(parseInt(document.getElementById('editFundamentalPulseConstant').value), 4, 1);
            const harmonicPulse = numberToBytes(parseInt(document.getElementById('editHarmonicPulseConstant').value), 4, 1);
            
            frame.push(...fundamentalPulse.map(add33));
            frame.push(...harmonicPulse.map(add33));
            frame.push(0x33, 0x33, 0x33, 0x33, 0xDD);
            frame.push(0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xDD);
            
            // Checksum
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Compose harmonic count from parsed data
        function composeHarmonicCountFromParsed() {
            const HEADER = [0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 
                           0x14, 0x41, 0x0E, 0x12, 0x12, 0x37, 0x35, 0x33, 0x33, 0x33, 0x37, 0x36, 
                           0x35, 0x34, 0x35, 0x39, 0x12, 0x0E, 0xBB, 0xBB, 0xBB, 0xBB];
            
            const frame = [...HEADER];
            
            // DD 37 (Function code)
            frame.push(0xDD, 0x37, 0xDD, 0x32, 0x32, 0xDD, 0x32, 0x32, 0x32, 0x32, 0x43, 0x33, 0x33, 0x33);
            
            const harmonicOrder = parseInt(document.getElementById('editCurrentHarmonicOrder').value);
            const orderIndex = parseInt(document.getElementById('editCurrentHarmonicOrderIndex').value);
            
            frame.push(0x33); // Reserved
            frame.push(add33(harmonicOrder));
            frame.push(add33(orderIndex));
            frame.push(0x33, 0xDD);
            frame.push(0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xDD);
            
            // Checksum
            const checksum = calculateChecksum(frame.slice(frame.indexOf(0x68)));
            frame.push(checksum);
            frame.push(0x16);
            
            return frame;
        }

        // Serial communication functions
        async function refreshPorts() {
            try {
                const ports = await navigator.serial.getPorts();
                const portSelect = document.getElementById('serialPort');
                portSelect.innerHTML = '<option value="">Select Port...</option>';
                
                ports.forEach(port => {
                    const option = document.createElement('option');
                    option.value = port.getInfo().usbVendorId + ':' + port.getInfo().usbProductId;
                    option.textContent = port.getInfo().usbVendorId ? 
                        `USB Device (VID:${port.getInfo().usbVendorId}, PID:${port.getInfo().usbProductId})` : 
                        'Serial Port';
                    portSelect.appendChild(option);
                });
                
                if (ports.length === 0) {
                    portSelect.innerHTML = '<option value="">No ports available</option>';
                }
                
                logMessage('Ports refreshed. Found ' + ports.length + ' port(s).');
            } catch (error) {
                logMessage('Error refreshing ports: ' + error.message);
            }
        }

        async function connectSerial() {
            try {
                const baudRate = parseInt(document.getElementById('baudRate').value);
                const dataBits = parseInt(document.getElementById('dataBits').value);
                const stopBits = parseInt(document.getElementById('stopBits').value);
                const parity = document.getElementById('parity').value;

                // Request port access (this will show a dialog for user to select port)
                serialPort = await navigator.serial.requestPort();
                
                // Configure port
                await serialPort.open({
                    baudRate: baudRate,
                    dataBits: dataBits,
                    stopBits: stopBits,
                    parity: parity
                });

                writer = serialPort.writable.getWriter();
                reader = serialPort.readable.getReader();
                isConnected = true;

                // Update UI
                document.getElementById('connectBtn').disabled = true;
                document.getElementById('disconnectBtn').disabled = false;
                document.getElementById('testFrameSelect').disabled = false;
                document.getElementById('sendBtn').disabled = false;
                document.getElementById('sendAllBtn').disabled = false;
                document.getElementById('serialPort').disabled = true;

                logMessage('Connected to serial port successfully.');
                logMessage(`Configuration: ${baudRate} baud, ${dataBits} data bits, ${stopBits} stop bits, ${parity} parity`);

                // Start reading responses
                readSerialData();

            } catch (error) {
                logMessage('Connection failed: ' + error.message);
                alert('Failed to connect to serial port: ' + error.message);
            }
        }

        async function disconnectSerial() {
            try {
                if (writer) {
                    writer.releaseLock();
                    writer = null;
                }
                if (reader) {
                    reader.releaseLock();
                    reader = null;
                }
                if (serialPort) {
                    await serialPort.close();
                    serialPort = null;
                }
                
                isConnected = false;

                // Update UI
                document.getElementById('connectBtn').disabled = false;
                document.getElementById('disconnectBtn').disabled = true;
                document.getElementById('testFrameSelect').disabled = true;
                document.getElementById('sendBtn').disabled = true;
                document.getElementById('sendAllBtn').disabled = true;
                document.getElementById('serialPort').disabled = false;

                logMessage('Disconnected from serial port.');

            } catch (error) {
                logMessage('Error disconnecting: ' + error.message);
            }
        }

        async function readSerialData() {
            try {
                while (isConnected && reader) {
                    const { value, done } = await reader.read();
                    if (done) break;
                    
                    // Convert Uint8Array to hex string
                    const hexString = Array.from(value)
                        .map(byte => byte.toString(16).toUpperCase().padStart(2, '0'))
                        .join(' ');
                    
                    logMessage('RX: ' + hexString);
                }
            } catch (error) {
                if (isConnected) {
                    logMessage('Error reading serial data: ' + error.message);
                }
            }
        }

        async function sendTestFrame() {
            if (!isConnected || !writer) {
                alert('Please connect to serial port first.');
                return;
            }

            const frameIndex = parseInt(document.getElementById('testFrameSelect').value) - 1;
            if (frameIndex < 0 || frameIndex >= testFrames.length) {
                alert('Please select a valid test frame.');
                return;
            }

            try {
                const frameHex = testFrames[frameIndex];
                const bytes = frameHex.split(' ').map(hex => parseInt(hex, 16));
                const data = new Uint8Array(bytes);

                await writer.write(data);
                logMessage(`TX Frame ${frameIndex + 1}: ${frameHex}`);

            } catch (error) {
                logMessage('Error sending frame: ' + error.message);
            }
        }

        async function sendAllFrames() {
            if (!isConnected || !writer) {
                alert('Please connect to serial port first.');
                return;
            }

            const delay = parseInt(document.getElementById('frameDelay').value);
            const confirmSend = confirm(`Send all 21 test frames with ${delay}ms delay between frames?`);
            
            if (!confirmSend) return;

            try {
                document.getElementById('sendAllBtn').disabled = true;
                logMessage('Starting to send all test frames...');

                for (let i = 0; i < testFrames.length; i++) {
                    const frameHex = testFrames[i];
                    const bytes = frameHex.split(' ').map(hex => parseInt(hex, 16));
                    const data = new Uint8Array(bytes);

                    await writer.write(data);
                    logMessage(`TX Frame ${i + 1}/21: ${frameHex}`);

                    if (i < testFrames.length - 1) {
                        await new Promise(resolve => setTimeout(resolve, delay));
                    }
                }

                logMessage('All test frames sent successfully!');
                document.getElementById('sendAllBtn').disabled = false;

            } catch (error) {
                logMessage('Error sending frames: ' + error.message);
                document.getElementById('sendAllBtn').disabled = false;
            }
        }

        function clearSerialLog() {
            document.getElementById('serialLog').innerHTML = '';
        }

        function logMessage(message) {
            const log = document.getElementById('serialLog');
            const timestamp = new Date().toLocaleTimeString();
            const logEntry = document.createElement('div');
            logEntry.innerHTML = `[${timestamp}] ${message}`;
            log.appendChild(logEntry);
            log.scrollTop = log.scrollHeight;
        }

        // Initialize display
        showCalibrationForm();
        
        // Initialize serial port list on page load
        window.addEventListener('load', () => {
            refreshPorts();
        });
    </script>
</body>
</html>